package main

import "time"

type FcmRequest struct {
	ValidateOnly bool     `json:"validate_only,omitempty"`
	Message      *Message `json:"message,omitempty"`
}

// Message to be sent via Firebase Cloud Messaging.
//
// Message contains payload data, recipient information and platform-specific configuration
// options. A Message must specify exactly one of Token, Topic or Condition fields. Apart from
// that a Message may specify any combination of Data, Notification, Android, Webpush and APNS
// fields. See https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages for more
// details on how the backend FCM servers handle different message parameters.
type Message struct {
	Data         map[string]string `json:"data,omitempty"`
	Notification *Notification     `json:"notification,omitempty"`
	Android      *AndroidConfig    `json:"android,omitempty"`
	Webpush      *WebpushConfig    `json:"webpush,omitempty"`
	APNS         *APNSConfig       `json:"apns,omitempty"`
	FCMOptions   *FCMOptions       `json:"fcm_options,omitempty"`
	Token        string            `json:"token,omitempty"`
	Topic        string            `json:"-"`
	Condition    string            `json:"condition,omitempty"`
}

// FCMOptions contains additional options to use across all platforms.
type FCMOptions struct {
	AnalyticsLabel string `json:"analytics_label,omitempty"`
}

// Notification is the basic notification template to use across all platforms.
type Notification struct {
	Title    string `json:"title,omitempty"`
	Body     string `json:"body,omitempty"`
	ImageURL string `json:"image,omitempty"`
}

// AndroidConfig contains messaging options specific to the Android platform.
type AndroidConfig struct {
	CollapseKey           string               `json:"collapse_key,omitempty"`
	Priority              string               `json:"priority,omitempty"` // one of "normal" or "high"
	TTL                   *time.Duration       `json:"-"`
	RestrictedPackageName string               `json:"restricted_package_name,omitempty"`
	Data                  map[string]string    `json:"data,omitempty"` // if specified, overrides the Data field on Message type
	Notification          *AndroidNotification `json:"notification,omitempty"`
	FCMOptions            *AndroidFCMOptions   `json:"fcm_options,omitempty"`
}

// AndroidNotification is a notification to send to Android devices.
type AndroidNotification struct {
	Title                 string                        `json:"title,omitempty"` // if specified, overrides the Title field of the Notification type
	Body                  string                        `json:"body,omitempty"`  // if specified, overrides the Body field of the Notification type
	Icon                  string                        `json:"icon,omitempty"`
	Color                 string                        `json:"color,omitempty"` // notification color in #RRGGBB format
	Sound                 string                        `json:"sound,omitempty"`
	Tag                   string                        `json:"tag,omitempty"`
	ClickAction           string                        `json:"click_action,omitempty"`
	BodyLocKey            string                        `json:"body_loc_key,omitempty"`
	BodyLocArgs           []string                      `json:"body_loc_args,omitempty"`
	TitleLocKey           string                        `json:"title_loc_key,omitempty"`
	TitleLocArgs          []string                      `json:"title_loc_args,omitempty"`
	ChannelID             string                        `json:"channel_id,omitempty"`
	ImageURL              string                        `json:"image,omitempty"`
	Ticker                string                        `json:"ticker,omitempty"`
	Sticky                bool                          `json:"sticky,omitempty"`
	EventTimestamp        *time.Time                    `json:"-"`
	LocalOnly             bool                          `json:"local_only,omitempty"`
	Priority              AndroidNotificationPriority   `json:"-"`
	VibrateTimingMillis   []int64                       `json:"-"`
	DefaultVibrateTimings bool                          `json:"default_vibrate_timings,omitempty"`
	DefaultSound          bool                          `json:"default_sound,omitempty"`
	LightSettings         *LightSettings                `json:"light_settings,omitempty"`
	DefaultLightSettings  bool                          `json:"default_light_settings,omitempty"`
	Visibility            AndroidNotificationVisibility `json:"-"`
	NotificationCount     *int                          `json:"notification_count,omitempty"`
}

// AndroidNotificationPriority represents the priority levels of a notification.
type AndroidNotificationPriority int

const (
	priorityUnspecified AndroidNotificationPriority = iota

	// PriorityMin is the lowest notification priority. Notifications with this priority might not
	// be shown to the user except under special circumstances, such as detailed notification logs.
	PriorityMin

	// PriorityLow is a lower notification priority. The UI may choose to show the notifications
	// smaller, or at a different position in the list, compared with notifications with PriorityDefault.
	PriorityLow

	// PriorityDefault is the default notification priority. If the application does not prioritize
	// its own notifications, use this value for all notifications.
	PriorityDefault

	// PriorityHigh is a higher notification priority. Use this for more important
	// notifications or alerts. The UI may choose to show these notifications larger, or at a
	// different position in the notification lists, compared with notifications with PriorityDefault.
	PriorityHigh

	// PriorityMax is the highest notification priority. Use this for the application's most
	// important items that require the user's prompt attention or input.
	PriorityMax
)

// AndroidNotificationVisibility represents the different visibility levels of a notification.
type AndroidNotificationVisibility int

const (
	visibilityUnspecified AndroidNotificationVisibility = iota

	// VisibilityPrivate shows this notification on all lockscreens, but conceal sensitive or
	// private information on secure lockscreens.
	VisibilityPrivate

	// VisibilityPublic shows this notification in its entirety on all lockscreens.
	VisibilityPublic

	// VisibilitySecret does not reveal any part of this notification on a secure lockscreen.
	VisibilitySecret
)

// LightSettings to control notification LED.
type LightSettings struct {
	Color                  string
	LightOnDurationMillis  int64
	LightOffDurationMillis int64
}

// AndroidFCMOptions contains additional options for features provided by the FCM Android SDK.
type AndroidFCMOptions struct {
	AnalyticsLabel string `json:"analytics_label,omitempty"`
}

// WebpushConfig contains messaging options specific to the WebPush protocol.
//
// See https://tools.ietf.org/html/rfc8030#section-5 for additional details, and supported
// headers.
type WebpushConfig struct {
	Headers      map[string]string    `json:"headers,omitempty"`
	Data         map[string]string    `json:"data,omitempty"`
	Notification *WebpushNotification `json:"notification,omitempty"`
	FcmOptions   *WebpushFcmOptions   `json:"fcm_options,omitempty"`
}

// WebpushNotificationAction represents an action that can be performed upon receiving a WebPush notification.
type WebpushNotificationAction struct {
	Action string `json:"action,omitempty"`
	Title  string `json:"title,omitempty"`
	Icon   string `json:"icon,omitempty"`
}

// WebpushNotification is a notification to send via WebPush protocol.
//
// See https://developer.mozilla.org/en-US/docs/Web/API/notification/Notification for additional
// details.
type WebpushNotification struct {
	Actions            []*WebpushNotificationAction `json:"actions,omitempty"`
	Title              string                       `json:"title,omitempty"` // if specified, overrides the Title field of the Notification type
	Body               string                       `json:"body,omitempty"`  // if specified, overrides the Body field of the Notification type
	Icon               string                       `json:"icon,omitempty"`
	Badge              string                       `json:"badge,omitempty"`
	Direction          string                       `json:"dir,omitempty"` // one of 'ltr' or 'rtl'
	Data               interface{}                  `json:"data,omitempty"`
	Image              string                       `json:"image,omitempty"`
	Language           string                       `json:"lang,omitempty"`
	Renotify           bool                         `json:"renotify,omitempty"`
	RequireInteraction bool                         `json:"requireInteraction,omitempty"`
	Silent             bool                         `json:"silent,omitempty"`
	Tag                string                       `json:"tag,omitempty"`
	TimestampMillis    *int64                       `json:"timestamp,omitempty"`
	Vibrate            []int                        `json:"vibrate,omitempty"`
	CustomData         map[string]interface{}
}

// WebpushFcmOptions contains additional options for features provided by the FCM web SDK.
type WebpushFcmOptions struct {
	Link string `json:"link,omitempty"`
}

// APNSConfig contains messaging options specific to the Apple Push Notification Service (APNS).
//
// See https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html
// for more details on supported headers and payload keys.
type APNSConfig struct {
	Headers    map[string]string `json:"headers,omitempty"`
	Payload    *APNSPayload      `json:"payload,omitempty"`
	FCMOptions *APNSFCMOptions   `json:"fcm_options,omitempty"`
}

// APNSFCMOptions contains additional options for features provided by the FCM Aps SDK.
type APNSFCMOptions struct {
	AnalyticsLabel string `json:"analytics_label,omitempty"`
	ImageURL       string `json:"image,omitempty"`
}

// APNSPayload is the payload that can be included in an APNS message.
//
// The payload mainly consists of the aps dictionary. Additionally it may contain arbitrary
// key-values pairs as custom data fields.
//
// See https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html
// for a full list of supported payload fields.
type APNSPayload struct {
	Aps        *Aps                   `json:"aps,omitempty"`
	CustomData map[string]interface{} `json:"-"`
}

// Aps represents the aps dictionary that may be included in an APNSPayload.
//
// Alert may be specified as a string (via the AlertString field), or as a struct (via the Alert
// field).
type Aps struct {
	AlertString      string                 `json:"-"`
	Alert            *ApsAlert              `json:"-"`
	Badge            *int                   `json:"badge,omitempty"`
	Sound            string                 `json:"-"`
	CriticalSound    *CriticalSound         `json:"-"`
	ContentAvailable bool                   `json:"-"`
	MutableContent   bool                   `json:"-"`
	Category         string                 `json:"category,omitempty"`
	ThreadID         string                 `json:"thread-id,omitempty"`
	CustomData       map[string]interface{} `json:"-"`
}

// ApsAlert is the alert payload that can be included in an Aps.
//
// See https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html
// for supported fields.
type ApsAlert struct {
	Title           string   `json:"title,omitempty"` // if specified, overrides the Title field of the Notification type
	SubTitle        string   `json:"subtitle,omitempty"`
	Body            string   `json:"body,omitempty"` // if specified, overrides the Body field of the Notification type
	LocKey          string   `json:"loc-key,omitempty"`
	LocArgs         []string `json:"loc-args,omitempty"`
	TitleLocKey     string   `json:"title-loc-key,omitempty"`
	TitleLocArgs    []string `json:"title-loc-args,omitempty"`
	SubTitleLocKey  string   `json:"subtitle-loc-key,omitempty"`
	SubTitleLocArgs []string `json:"subtitle-loc-args,omitempty"`
	ActionLocKey    string   `json:"action-loc-key,omitempty"`
	LaunchImage     string   `json:"launch-image,omitempty"`
}

// CriticalSound is the sound payload that can be included in an Aps.
type CriticalSound struct {
	Critical bool    `json:"-"`
	Name     string  `json:"name,omitempty"`
	Volume   float64 `json:"volume,omitempty"`
}
